#ifndef _STREAMINGCHAN_MATRIX_
#define _STREAMINGCHAN_MATRIX_

#include<iostream>
#include<new>
#include<vector>
#include<exception>
#include<cmath>
#include<limite>


///接下来定义要求的矩阵向量类 Matrix 含有 n_row n_col 属性来表示行列，用指针T*操作元素matrix_elements 有用于判断是否为方阵的函数 is_square()
///这次作业中大量代码参考了任课老师的gitee，也就是用那个方阵模板的思路依样画葫芦，很多有点懵的地方请别介意
///因为还没熟悉纯键盘操作，所以还是用了GUI版本的emacs
///老样子，几周之后还是没装好doxymacs，所以标准化注释是不存在的

template <typename T>
class Matrix;

template <typename T>
Matrix<T> operator*(const Matrix<T> & lhs,const Matrix<T> & rhs)
///后来看了看才发现lhs和rhs是left/right hand side 的意思，这几行先定义需要的运算符和模板类

template <typename T>
Matrix<T> operator+(const Matrix<T> & rhs, const Matrix<T> & lhs);

template <typename T>
Matrix<T> operator-(const Matrix<T> & rhs, const Matrix<T> & lhs);

template <typename T>
class Matrix
-{
///终于开始定义matrix模板了
private:
	int n_row = 0;
	int n_col = 0;
	T *matrix_element = nullptr;
	void alloc_memory(int _d);
	void release_memory();		
	void copy_elements(T* _t, T const* _s, int n);
	/// 初始化行列参数，和用来存放矩阵元素的空间，提供两个用来管理内存的函数和一个用来复制矩阵的函数？（memory是我照抄老师gitee的。。。）
public:
	Matrix();
	Matrix(const int _m, const int _n);
	Matrix(const Matrix<T> & rhs);
	Matrix(Matrix && _s);	
	~Matrix();
	Matrix<T> & operator= (const Matrix<T> & rhs);
	Matrix<T> & operator= (Matrix<T> && rhs);
	T & operator()(int _i, int _j) const;
	void exit_abnormal(int _code) const;
	///前几个是标准的构造函数，一个析构函数之后有用 额 异常退出那个也是模仿老师的，但是写不太来
	
	bool is_square();
	void load();
	void print();
	int size(int _no) const;
	friend Matrix<T> operator* <>(const Matrix<T> & lhs, const Matrix<T> & rhs);	
	friend Matrix<T> operator+ <>(const Matrix<T> & lhs, const Matrix<T> & rhs);
	friend Matrix<T> operator- <>(const Matrix<T> & lhs, const Matrix<T> & rhs);
	///提供题目要求的判断函数和基本运算函数，还有如同字面意思上的输入输出
};

///这一部分就开始写重载的各种情况下的对象构建了
template <typename T>
Matrix<T>::Matrix()
{
	n_row = 0;
	n_col = 0;
	matrix_element = nullptr;
};

template <typename T>
Matrix<T>::Matrix(const int _m, const int _n)
{
	n_row = _n;
	n_col = _m;
	if (n_row <= 0 || n_col <=0)
		exit_abnormal(1);
		///下标越界时的故障退出，翻上学期程序基础的作业时才想起来，靠，我忘了row和col啥意思了
	else 
		alloc_memory(_m * _n);
};

template <typename T>
Matrix<T>::Matrix(const Matrix<T> & rhs)
{
	n_row = rhs.n_row;
	n_col = rhs.n_col;
		alloc_memory(n_row * n_col);
		copy_elements(mat, rhs.mat, n_row * n_col);
};

template <typename T>
Matrix<T>::Matrix(Matrix<T> && rhs)
{
	m = rhs.n_row;
	n = rhs.n_col;
		matrix_element = rhs.matrix_element;
		rhs.n_row = 0;
		rhs.n_col = 0;
};
///一个是用来复制，一个是用来转移的


template <typename T>
Matrix<T> & Matrix<T>::operator=(const Matrix<T> & rhs)
{
	n_row = rhs.matrix_element;
	n_col = rhs.n_col;
	release_memory();
	if (rhs.matrix_element != nullptr)
	{
		alloc_memory(m * n);
		copy_elements(matrix_element, rhs.matrix_element,n_row * n_col);
	}else 
		mat = nullptr;
	return *this;
};

template <typename T>
Matrix<T> & Matrix<T>::operator=(Matrix<T> && rhs)
{
	m = rhs.n_row;
	n = rhs.n_col;
	release_memory();
	if (rhs.matrix_element != nullptr){
		alloc_memory(n_row * n_col);
		copy_elements(matrix_element, rhs.matrix_element,n_row * n_col);
	}else 
		matrix_element = nullptr;
	return *this;
};

template <typename T>
T & Matrix<T>::operator()(int _i, int _j) const
{
	if (_i < 0 || _i >= n_row || _j < 0 || _j >= n_col)
		exit_abnormal(1);
	T & value = mat[_i * n_col + _j];
	return value;
};

template <typename T>
Matrix<T> operator*(const Matrix<T> & lhs, const Matrix<T> & rhs)
{
	if (lhs.n_col != rhs.n_row)
		lhs.exit_abnormal(2);
	Matrix<T> product(lhs.n_row, rhs.n_col);
	for (int i = 0; i < lhs.n_row; i++)
		for (int j = 0; j < rhs.n_col; j++){
			T sum = 0;
			for (int k = 0; k < lhs.m; k++)
				sum += lhs.matrix_element[i * lhs.n_col + k] * rhs.matrix_element[k * rhs.n_col + j];
			product(i, j) = sum;
		}
	return product;
};

template <typename T>
Matrix<T> operator+(const Matrix<T> & lhs, const Matrix<T> & rhs)
{
	if (lhs.m != rhs.m || lhs.n != rhs.n)
		lhs.exit_abnormal(2);
	Matrix<T> sum(lhs.m, lhs.n);
	for (int i = 0; i < lhs.m; i++)
		for (int j = 0; j < lhs.n; j++){
			sum(i, j) = lhs.mat[i * lhs.n + j] + rhs.mat[i * rhs.n + j];
		}
	return sum;
};

template <typename T>
Matrix<T> operator-(const Matrix<T> & lhs, const Matrix<T> & rhs)
{
	if (lhs.n_row != rhs.n_row || lhs.n_col != rhs.n_col)
		lhs.exit_abnormal(2);
	Matrix<T> sub(lhs.n_row, lhs.n_col);
	for (int i = 0; i < lhs.n_row; i++)
		for (int j = 0; j < lhs.n_col; j++){
			sub(i, j) = lhs.mat[i * lhs.n_col + j] - rhs.mat[i * rhs.n_col + j];
		}
	return sub;
};

template <typename T>
void Matrix<T>::write()
{
	cout << "请输入元素" << endl;
	for (int i = 0; i < n_row; i++)
		for (int j = 0; j < n_col; j++)
			cin >> mat[i * n_col + j];
};

template <typename T>
void Matrix<T>::read() const
{
	for (int i = 0; i < n_row; i++)
	{
		for (int j = 0; j < n_col; j++)
			cout << mat[i * n_row + j] << "\t";
		cout << endl;
	}
};

template <typename T>
int Matrix<T>::size(int _no) const{
	if (_no == 1)
		return n_row;
	else if (_no == 2)
		return n_col;
	else
		cout << "Invalid index." << endl;
};

template <typename T>
void Matrix<T>::copy_elements(T* _t, T const* _s, int _n){
	for (int i = 0; i < _n; i++)
		_t[i] = _s[i];
};

template <typename T>
bool Matrix<T>::is_square(){
	if (n_row == n_col)
		return true;
	else 
		return false;
};
///这个函数好轻松，说起来行列我本来直接用mn不行吗。。。打 n_row好烦的

template <typename T>
Matrix<T>::~Matrix(){
	n_col = 0;
	n_row = 0;
	release_memory();
};
///析构函数这里用上了，清理后事来着？

template <typename T>
void Matrix<T>::alloc_memory(int _no)
{
	matrix_element = new T[_no];
};

template <typename T>
void Matrix<T>::release_memory()
{
	delete [] matrix_element;
	matrix_element = nullptr;
};
///这两个是内存管理用的，说起来看了一下我似乎忘了缩进了

template <typename T>
void Matrix<T>::exit_abnormal(int _code) const
{
	switch(_code)
	{
		case 1: cerr << "下标越界？" << endl; 
			break;
		case 2: cerr << "维数出问题了？" << endl; 
			break;
		default: cerr << "不知道咋啦" << endl; break;
	}
	exit(-1);
};
///上面这个是异常退出机制，说实话，算了，我忘了我想说啥了

/* The Col_vector class
template <typename T>
class Col_vector;

template <typename T>
T operator*(const Col_vector<T> & lhs, const Col_vector<T> & rhs);
*/
///写不玩row和col的部分了。。。。好吧我不应该在还没搞懂这门语言的前提下在ddl当天写作业的，留一个开头以后再说吧

#else
///框架部分依样画葫芦...估计还得再研究一下 Do nothing
#endif
